/*
 * Copyright 2006-2008 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.martinimix.context.support;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanNotOfRequiredTypeException;

import com.bluemartini.dna.BMContext;
import com.bluemartini.dna.DomainDictionary;
import com.bluemartini.dna.DomainElement;
import com.bluemartini.dna.DynamicDomainListener;
import com.bluemartini.dna.DynamicDomainManager;

/**
 * Provides a reference data service using a Blue Martini domain dictionary
 * as its provider.
 * 
 * @author Scott Rossillo
 *
 */
public final class BlueMartiniDomainDictionaryService implements ReferenceDataService {
	
	private final static Log log = LogFactory.getLog(BlueMartiniDomainDictionaryService.class);
	
	private Set dynamicDomainListeners = null;

	/**
	 * Returns the Blue Martini domain element with the given name.
	 * 
	 * @param name the name of the <code>DomainElement</code> to return
	 * 
	 * @return the <code>DomainElement</code> identified by the given
	 * <code>name</code>
	 */
	protected final DomainElement getDomainElement(String name) {
		
		if(name == null) {
			throw new IllegalArgumentException("Refernece data [name] cannot be null!");
		}
		
		DomainDictionary dictionary = BMContext.getDomainDictionary();

		log.info("Registering dynamic domain listeners for current thread");
		registerDynamicDomainListeners();
		
		log.info("Returing domain element [" + name + "]");
		
		return dictionary.getDomainElement(name);
	}
	
	/* (non-Javadoc)
	 * @see net.martinimix.controller.support.ReferenceDataService#getReferenceData(java.lang.String)
	 */
	public Map getReferenceData(String name) {
		
		if(log.isDebugEnabled()) {
			log.debug("Handling reference data request for [" + name + "]");
		}
		
		return new BlueMartiniDomainDictionaryDataMap(this.getDomainElement(name));
	}
	
	/* (non-Javadoc)
	 * @see net.martinimix.controller.support.ReferenceDataService#getNotSelectedKey(java.lang.String)
	 */
	public String getNotSelectedKey(String name) {
		
		DomainElement element = this.getDomainElement(name);
		
		return element.getNotSelectedValue().getString("code");
	}
	
	/**
	 * Registers this services dynamic domain listeners with Blue Martini's
	 * domain dictionary.
	 */
	protected final void registerDynamicDomainListeners() {
		
		if(dynamicDomainListeners == null) {
			return;
		}
		
		DynamicDomainManager dynamicDomainManager = DomainDictionary.getDynamicDomainManagerForThread();
		Iterator it = dynamicDomainListeners.iterator();
		DynamicDomainListener listener;

		if(dynamicDomainManager == null) {
			dynamicDomainManager = new DynamicDomainManager();
			DomainDictionary.setDynamicDomainManagerForThread(dynamicDomainManager);
		}
		
		while(it.hasNext()) {
			listener = (DynamicDomainListener) it.next();
			dynamicDomainManager.addDynamicDomainListener(listener);
			
			if(log.isDebugEnabled()) {
				log.debug("Registered [" + listener + "] for domains [" + listener.supportedDynamicDomains() + "]" );
			}
		}
		
	}
	
	/**
	 * Returns a list of dynamic domain listeners registered with this
	 * reference data service.
	 * 
	 * @return a <code>Set</code> containing all of the 
	 * <code>DynamicDomainListener</code>s registered with this service
	 */
	public Set getDynamicDomainListeners() {
		
		return this.dynamicDomainListeners;
	}
	
	/**
	 * Sets the dynamic domain listeners this service will register with
	 * Blue Martini's domain dictionary.
	 * 
	 * @param dynamicDomainListeners a <code>Set</code> of dynamic domain
	 * listeners this service will register in the 
	 * <code>DomainDictionary</code>
	 */
	public void setDynamicDomainListeners(Set dynamicDomainListeners) {
	
		Iterator it = dynamicDomainListeners.iterator();
		Object listener;
		
		this.dynamicDomainListeners = dynamicDomainListeners;
		
		while(it.hasNext()) {
			listener = it.next();
			if(!DynamicDomainListener.class.isAssignableFrom(listener.getClass())) {
				throw new BeanNotOfRequiredTypeException(
						"dynamicDomainListeners", DynamicDomainListener.class, listener.getClass());
			}
		}	
	}
	
}
